//
// EchoServer.cpp
//
// $Id: //poco/1.4/Net/samples/EchoServer/src/EchoServer.cpp#1 $
//
// This sample demonstrates the SocketReactor and SocketAcceptor classes.
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier:	BSL-1.0
//


#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/SocketAcceptor.h"
#include "Poco/Net/SocketNotification.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/NObserver.h"
#include "Poco/Exception.h"
#include "Poco/Thread.h"
#include "Poco/FIFOBuffer.h"
#include "Poco/Delegate.h"
#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include <iostream>
#include "Buffer.h"
using namespace DemoTcpServer;

using Poco::Net::SocketReactor;
using Poco::Net::SocketAcceptor;
using Poco::Net::ReadableNotification;
using Poco::Net::WritableNotification;
using Poco::Net::ShutdownNotification;
using Poco::Net::ServerSocket;
using Poco::Net::StreamSocket;
using Poco::NObserver;
using Poco::AutoPtr;
using Poco::Thread;
using Poco::FIFOBuffer;
using Poco::delegate;
using Poco::Util::ServerApplication;
using Poco::Util::Application;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;

struct TcpMessage
{
	int msgType; // 0-text, 1-json, 2-xml
	std::string content;
};

struct TcpClient
{
	Buffer			inputBuffer;	// input message queue
	Buffer			outputBuffer;	// output message queue
	StreamSocket	socket;			// socket handler
};

class TcpServiceHandler
	/// I/O handler class. This class (un)registers handlers for I/O based on
	/// data availability. To ensure non-blocking behavior and alleviate spurious
	/// socket writability callback triggering when no data to be sent is available.
{
public:
	enum { HEADER_LENGTH = 4 };
	enum { MESSAGE_TYPE_LENGTH = 4 };

	TcpServiceHandler(StreamSocket& socket, SocketReactor& reactor):
		_reactor(reactor)
	{
		_client.socket = socket;
		Application& app = Application::instance();
		app.logger().information("Connection from " + _client.socket.peerAddress().toString());

		_reactor.addEventHandler(_client.socket, NObserver<TcpServiceHandler, ReadableNotification>(*this, &TcpServiceHandler::onSocketReadable));
		//_reactor.addEventHandler(_client.socket, NObserver<TcpServiceHandler, WritableNotification>(*this, &TcpServiceHandler::onSocketWritable));
		_reactor.addEventHandler(_client.socket, NObserver<TcpServiceHandler, ShutdownNotification>(*this, &TcpServiceHandler::onSocketShutdown));
	}
	
	~TcpServiceHandler()
	{
		Application& app = Application::instance();
		try
		{
			app.logger().information("Disconnecting " + _client.socket.peerAddress().toString());
		}
		catch (...)
		{
		}
		_reactor.removeEventHandler(_client.socket, NObserver<TcpServiceHandler, ReadableNotification>(*this, &TcpServiceHandler::onSocketReadable));
		//_reactor.removeEventHandler(_client.socket, NObserver<TcpServiceHandler, WritableNotification>(*this, &TcpServiceHandler::onSocketWritable));
		_reactor.removeEventHandler(_client.socket, NObserver<TcpServiceHandler, ShutdownNotification>(*this, &TcpServiceHandler::onSocketShutdown));
	}
	
	void onSocketReadable(const AutoPtr<ReadableNotification>& pNf);
	
	void onSocketWritable(const AutoPtr<WritableNotification>& pNf);

	void onSocketShutdown(const AutoPtr<ShutdownNotification>& pNf)
	{
		delete this;
	}

private:
	void onBufferMessage();
	void doDataAnalyze();
	void internalSendMessage();
	
private:
	
	SocketReactor& _reactor;
	TcpClient _client;
};

